package de.saarland.uni.lego3d.server.gui;

import java.util.Vector;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Locale;
import javax.media.j3d.View;
import javax.media.j3d.VirtualUniverse;

import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.universe.Viewer;
import com.sun.j3d.utils.universe.ViewingPlatform;

/** **************************************************************************
 * <pre>
 * This class is based on MultiUniverse.java from Virtual Worlds Productions
 * which I reproduce the disclaimer below.
 *
 * This class allow several Canvas3D for a single Scenegraph.
 * I try to mimic SimpleUniverse behavior for all  Canvas, as well the
 * cleanup method.
 *
 * @see getViewingPlatform(int)
 * @see MultipleUniverse(Canvas3D[])
 * @see addCanvas3D(Canvas3D )
 *
 *
 * Alessandro Borges (2007)
 *
 *
 ** **************************************************************************
 *	MultiUniverse.java 0.9 BETA 25.1.2004
 *
 * Copyright (c) 2004 Virtual Worlds Productions
 * Email: virt...@gmx.de
 *
 * This program is free software; you can redistribute it and/or modify  it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option) any
 * later version.
 *
 * Please contact virt...@gmx.de if you are interested in a source
 * package which is not licensed under the GPL
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. VIRTUAL WORLDS PRODUCTIONS AND ITS
 * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
 * RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES.
 * IN NO EVENT WILL VIRTUAL WORLDS PRODUCTIONS OR ITS LICENSORS BE LIABLE FOR
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS
 * OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE
 * SOFTWARE, EVEN IF VIRTUAL WORLDS PRODUCTIONS HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 * <pre>
 *
 * *****************************************************************************
 *
 * This class sets up a user environment to quickly and easily get a Java 3D
 * program up and running with more than one View and Canvas3D. This class
 * bases on the SimpleUniverse and creates all the necessary objects on the
 * "view" side of the scene graph. Specifically, this class creates a locale,
 * ViewingPlatforms and Viewer objects (all with their default values).
 *
 */
public class MultipleUniverse extends VirtualUniverse
   {
  /**
   * Locale reference needed to create the "view" portion of the scene graph.
   */
   public Locale          locale;

  /**
   * Viewer reference needed to create the "view" portion of the scene graph.
   */
   private Vector<Viewer>   viewers = null;

  /**
	 * Creates a locale and prepares for the given number of transforms (and
	 * therefore View, ViewPlatform and Canvas3D objects). This constructor does
	 * not create the necessary views, to do that, use method
	 *
	 * @see #createView(Canvas3D canvas)
	 * @param numTransforms
	 *            The number of View-Transforms and Canvas3D objects which have
	 *            to becontrolled by this object
	 */
   public MultipleUniverse() {
		viewers = new Vector<Viewer>();
		locale = new Locale(this);
	}

   /**
	 * Just like SimpleUniverse, creates a locale, a single
	 * ViewingPlatform (with default values), and and a Viewer object. The
	 * Viewer object uses default values for everything but the canvas.
	 *
	 * @param canvas
	 *            The canvas to associate with the Viewer object. Passing in
	 *            null will cause this parameter to be ignored and a canvas to
	 *            be created by the utility.
	 * @param canvas
	 */
   public MultipleUniverse(Canvas3D canvas) {
	   viewers = new Vector<Viewer>();
	   locale = new Locale(this);
	   createView(canvas);
   }

   /**
	 * creates a locale, a single ViewingPlatform (with default values), and and
	 * a Viewer object. The Viewer object uses default values for everything but
	 * the canvas.
	 *
	 * @param canvases an array on Canvas3D
	 */
	public MultipleUniverse(Canvas3D[] canvases) {
		viewers = new Vector<Viewer>();
		locale = new Locale(this);

		// this is to be coerent with number of canvas and viewers index
		for(int i=0; i<canvases.length; i++) {
			addCanvas3D(canvases[i]);
		}

	}

   /**
    * Returns the Viewer/Canvas3D count attached to this MultipleUniverse.

    * @return a int value
    */
   public int getViewerCount() {
	   return viewers.size();
   }

  /**
   * This method attaches the given Canvas3D object to the universe and
   * creates the required ViewPlatform and View object for it. This method
   * has to be called as often as much numTransforms habe been specified for
   * this methods constructor. The created Viewer- and View objects can be
   * accessed using the appropriate get-methods. The required number is
   * identically with the number of createView()-calls related to the view.
   *
   * @param canvas the Canvas3D object which has to be attached to the
   *        Universe
   *
   * @return the View object which was created for this Canvas3Ds view
   */
   public View createView(Canvas3D canvas) {
		ViewingPlatform vwp = new ViewingPlatform();
		Viewer viewer = new Viewer(canvas);
		viewer.setViewingPlatform(vwp);
		this.viewers.add(viewer);
		locale.addBranchGraph(vwp);
        // TODO use old mode createViewer
		return viewer.getView();
	}

   /**
    * Same thing as createView(Canvas3D)
    *
    * @param canvas
    */
   public void addCanvas3D(Canvas3D canvas) {
	  createView(canvas);
   }

   /**
    * get the Viewer for Canvas3D #num
    *
    * @param num index of Canvas3D
    *
    * @return the viewer attached to Canvas3D #num
    *
    */
   public Viewer getViewer(int num) {
		if (num < viewers.size())
			return viewers.get(num);
		else
			return null;
	}

  /**
   * returns the n-th ViewingPlatform
   * @param num index on Viewer's ViewingPlatform
   * @return an ViewingPlatform or null if num less than 0 or greater than
   */
   public ViewingPlatform getViewingPlatform(int num) {

		Viewer viewer = getViewer(num);
		if (viewer == null)
			return null;
		return viewer.getViewingPlatform();
	}

  /***************************************************************************
	 * Used to add Nodes to the geometry side (as opposed to the view side) of
	 * the scene graph. This is a short cut to getting the Locale object and
	 * calling that object's addBranchGraph() method.
	 *
	 * @param bg
	 *            the BranchGroup to attach to this Universe's Locale.
	 */
   public void addBranchGraph(BranchGroup bg) {
		locale.addBranchGraph(bg);
	}

   /**
	 * Cleanup memory use and reference by this MultipleUniverse. Typically it
should
	 * be invoked by the applet's destroy method.
	 */
   public void cleanup() {
		for (Viewer viewer : viewers) {
			if (viewer != null) {
				View view = viewer.getView();
				// Issue 134: cleanup all off-screen canvases
				for (int i = view.numCanvas3Ds() - 1; i >= 0; i--) {
					Canvas3D c = view.getCanvas3D(i);
					if (c.isOffScreen()) {
						c.setOffScreenBuffer(null);
					}
				}

				// Remove all canvases from view; remove the viewing platform
				// from
				// this viewer; remove all locales to cleanup the scene graph
				view.removeAllCanvas3Ds();
				viewer.setViewingPlatform(null);
			}
		}
		removeAllLocales();

		// viewerMap cleanup here to prevent memory leak problem.
		Viewer.clearViewerMap();
		Primitive.clearGeometryCache();
	}

}